查看原文
其他

Flare-on5 Challenge6 magic -Writeup

蒼V嵐 看雪学院 2019-05-26

0x00 序 


  • Auth: vvv_347

  • Date: 09/14/2018

  • From: Flare-on5



0x01 破

signed __int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
 unsigned __int64 v3; // rax
 unsigned __int64 len; // rax
 __int64 *v6; // [rsp+0h] [rbp-1E0h]
 unsigned int seed; // [rsp+1Ch] [rbp-1C4h]
 unsigned int i; // [rsp+20h] [rbp-1C0h]
 unsigned int j; // [rsp+20h] [rbp-1C0h]
 unsigned int k; // [rsp+24h] [rbp-1BCh]
 char input_s[128]; // [rsp+40h] [rbp-1A0h]
 char a3a; // [rsp+C0h] [rbp-120h]
 char arr_1[72]; // [rsp+140h] [rbp-A0h]
 char v14; // [rsp+188h] [rbp-58h]
 unsigned __int64 v15; // [rsp+1C8h] [rbp-18h]

 v15 = __readfsqword(0x28u);
 seed = 0;
 memset(input_s, 0, sizeof(input_s));
 memset(&a3a, 0, 0x80uLL);
 *arr_1 = 0x45123A7920755C24LL;
 *&arr_1[8] = 0x17263719711D201ELL;
 *&arr_1[16] = 0x4A7C67303E100367LL;
 *&arr_1[24] = 0x11621308555E1B11LL;
 *&arr_1[32] = 0x122C17445A7C6C68LL;
 *&arr_1[40] = 0x576D0C6324095979LL;
 *&arr_1[48] = 0x265D0F6A0C27651FLL;
 *&arr_1[56] = 0xA375C1433594643LL;
 *&arr_1[64] = 0x2C16022663LL;
 memset(&v14, 0, 0x38uLL);
 for ( i = 0; i < strlen("Run, Forrest, run!!"); i += 4 )
   seed ^= *&aRunForrestRun[i];
 srand(seed);
 if ( sub_402D47() )
 {
   v3 = strlen(a2[1]);
   func_proc1(a2[1], v3, &a3a);
   func_proc2(*a2);
   puts("Generated first permutation!");
   exit(0);
 }
 puts("Welcome to the ever changing magic mushroom!");
 printf("%d trials lie ahead of you!\n", 666LL, a2);
 for ( j = 0; j < 666; ++j )
 {
   printf("Challenge %d/%d. Enter key: ", j + 1, 666LL);
   if ( !fgets(input_s, 128, unk_617630) )
     return 0xFFFFFFFFLL;
   len = strlen(input_s);
   func_proc1(input_s, len, &a3a);
   for ( k = 0; k < strlen(input_s); ++k )
     arr_1[k] ^= input_s[k];
   func_proc2(*v6);
 }
 printf("Congrats! Here is your price:\n%s\n", arr_1);
 return 0LL;
}


main生成个固定seed,之后进入sub_402D47做check,run时发现不会进入branch,先忽略。


接着读输入Key,进入func_proc1,完成后与加密flag做xor,最后进入func_proc2。


一共做666次Chanllenges,全部正确即可拿到flag。


Proc_1:

__int64 __fastcall func_proc1(char *input_s, unsigned __int64 len, char *a3)
{
 __int64 result; // rax
 char *dst; // [rsp+8h] [rbp-28h]
 unsigned int i; // [rsp+2Ch] [rbp-4h]

 dst = a3;
 for ( i = 0; ; ++i )                          // loop 34
 {
   result = i;
   if ( i >= 33uLL )
     break;
   if ( (func_list[i].len_p1 + func_list[i].len_p2) > len )// check1
     func_exit();
   func_xor(func_list[i].xor_func, func_list[i].xor_size, func_list[i].xor_data_pos);// ptr dec_smc
   if ( !(func_list[i].xor_func)(&input_s[func_list[i].len_p1], func_list[i].len_p2, func_list[i].x_data) )// check2 guess:smc
   {
     func_xor(func_list[i].xor_func, func_list[i].xor_size, func_list[i].xor_data_pos);
     func_exit();
   }
   func_xor(func_list[i].xor_func, func_list[i].xor_size, func_list[i].xor_data_pos);// smc enc_smc
   memcpy(&dst[func_list[i].dst_pos], &input_s[func_list[i].len_p1], func_list[i].len_p2);// update dst
 }
 return result;
}


可以明显看出是个解smc,调用,再复原smc的过程。

设计到有个0x120大小的数据结构。

xor_func: 被smc的函数地址
xor_size: 函数大小
len_p1: Start_addr,被Checkkey的起始地址
len_p2: len,被Checkkey的范围
xor_data_pos:用于解smc的数据
x_data: 调用被解smc函数时所需要的参数

一共Check33个函数,意味着就33个这样的结构体。 


我们可以手动跑一下得到解smc的函数。
使用脚本:

from struct import *

fp= open("magic", "rb+")

def dec_smc_core(func_addr, size, xor_addr, fp):
   fp.seek(0,0)
   file = fp.read()
   res = ''
   for i in range(size):
       res += chr(ord(file[func_addr+i]) ^ ord(file[xor_addr+i]))
   fp.seek(func_addr, 0)
   fp.write(res)

def dec_smc(fp):
   fp.seek(0x5100,0)
   f = fp.read()
   func_pos = ''
   for i in range(33):
       print "dp0", i
       xor_func, xor_size, len_p1, len_p2, dst_pos, xor_data_pos = unpack("<q4iq", f[i*0x120:i*0x120+32])
       func_pos += hex(xor_func)+'\n'
       xor_func -= 0x400000
       xor_data_pos -= 0x600000
       dec_smc_core(xor_func, xor_size, xor_data_pos, fp)
   open("smc_func_.txt", "w").write(func_pos)
   print "done"

dec_smc(fp)

可以拿到复原后的33个函数。

 

不难发现,这33个函数分为了7个种类:


  • 斐波那契数列

  • crc32

  • base64

  • 数组变换+xor_swap+xor

  • 字符异或

  • 字符相等

  • 字符偏移


于是,我们可以手动解一下(1/666)的Key:

from struct import *
import binascii
import base64
import string

Offst_xor_func = 0x00
Offst_func_size = 0x08
Offst_s_start_addr = 0x0c
Offst_s_len = 0x10
Offst_dst_pos = 0x14
Offst_xor_data_pos = 0x18
Offst_x_data = 0x20

fib_list = [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040, 1346269, 2178309, 3524578, 5702887, 9227465, 14930352, 24157817, 39088169, 63245986, 102334155, 165580141, 267914296, 433494437, 701408733, 1134903170, 1836311903, 2971215073, 4807526976, 7778742049, 12586269025, 20365011074, 32951280099, 53316291173, 86267571272, 139583862445, 225851433717, 365435296162, 591286729879, 956722026041, 1548008755920, 2504730781961, 4052739537881, 6557470319842, 10610209857723, 17167680177565, 27777890035288, 44945570212853, 72723460248141, 117669030460994, 190392490709135, 308061521170129, 498454011879264, 806515533049393, 1304969544928657, 2111485077978050, 3416454622906707, 5527939700884757, 8944394323791464, 14472334024676221, 23416728348467685, 37889062373143906, 61305790721611591, 99194853094755497, 160500643816367088, 259695496911122585, 420196140727489673, 679891637638612258, 1100087778366101931, 1779979416004714189, 2880067194370816120, 4660046610375530309, 7540113804746346429, 12200160415121876738, 1293530146158671551, 13493690561280548289, 14787220707439219840, 9834167195010216513, 6174643828739884737, 16008811023750101250, 3736710778780434371, 1298777728820984005, 5035488507601418376, 6334266236422402381, 11369754744023820757, 17704020980446223138, 10627031650760492279, 9884308557497163801, 2064596134548104464, 11948904692045268265, 14013500826593372729, 7515661444929089378, 3082418197812910491, 10598079642741999869, 13680497840554910360, 5831833409587358613, 1065587176432717357, 6897420586020075970, 7963007762452793327, 14860428348472869297, 4376692037216111008, 790376311979428689, 5167068349195539697, 5957444661174968386, 11124513010370508083, 17081957671545476469, 9759726608206432936, 8394940206042357789, 18154666814248790725, 8102862946581596898, 7810785687120836007]
orig_bs_table = [0x2A, 0x39, 0x5F, 0x64, 0xC2, 0xA7, 0x46, 0x23,
0x53, 0x6B, 0x74, 0x47, 0x28, 0x4D, 0x70, 0x42,
0x49, 0x25, 0x52, 0x6A, 0x62, 0x38, 0x40, 0x4A,
0x69, 0x45, 0x44, 0x59, 0x2D, 0x31, 0x24, 0x50,
0x67, 0x79, 0x54, 0x21, 0x4C, 0x76, 0x71, 0x66,
0x2B, 0x63, 0x68, 0x6D, 0x51, 0x57, 0x4F, 0x30,
0x65, 0x4E, 0x5A, 0x34, 0x75, 0x6E, 0x33, 0x6C,
0x37, 0x48, 0x26, 0x32, 0x77, 0x61, 0x7A, 0x4B]
for i in range(len(orig_bs_table)):
   orig_bs_table[i] = chr(orig_bs_table[i])

def dump_data_core(filename, data_addr, base_addr, size):
   fp= open(filename, "rb")
   offset = data_addr - base_addr
   fp.seek(offset,0)
   f = fp.read()
   type_format = '<' #default
   if size == 1:
       type_format += 'B'
   elif size == 2:
       type_format += 'H'
   elif size == 4:
       type_format += 'I'
   elif size == 8:
       type_format += 'Q'
   else:
       print "[warn]"
       type_format += 'x'
   target_data, = unpack(type_format, f[:size])
   return target_data

def dump_data_specific(filename, start_addr, base_addr, order, species, size, count):
   arr_data = []
   for i in range(count):
       data_addr = start_addr + 0x120*order + species + i*size
       arr_data.append(hex(dump_data_core(filename, data_addr, base_addr, size)))
   return arr_data

def explode_fib_num(dst):
   for i in range(len(fib_list)):
       if(dst == fib_list[i]):
           return i-1
   return "Error"

def spec_fib(key_1, key_pos, filename, start_addr, base_addr, order, species, size, count):
   res_arr = dump_data_specific(filename, start_addr, base_addr, order, species, size, count)
   print 'order:'+str(order)+' '+str(res_arr)
   for i in range(len(res_arr)):
       if(res_arr[i][-1] == 'L'):
           c = chr(explode_fib_num(int(res_arr[i][:-1] ,16)))
           key_1[key_pos+i] = c
       else:
           c = chr(explode_fib_num(int(res_arr[i],16)))
           key_1[key_pos+i] = c
   return key_1

def explode_crc32_c1(dst):
   if dst == 0x0:
       return ord('X')
   for i in range(31, 127):
       if(dst == binascii.crc32(chr(i)) &0xffffffff):
           return chr(i)
   return 'E1ROR'

def explode_crc32_c2(dst):
   if dst == 0x0:
       return ord('X')
   for x0 in range(31, 127):
       for x1 in range(31, 127):
           s = chr(x0) + chr(x1)
           if(binascii.crc32(s) &0xffffffff) == dst:
               return s
   return 'E2ROR'

def explode_crc32_c3(dst):
   if dst == 0x0:
       return ord('X')
   for x0 in range(31, 127):
       for x1 in range(31, 127):
           for x2 in range(31, 127):
               s = chr(x0) + chr(x1) + chr(x2)
               if(binascii.crc32(s) &0xffffffff) == dst:
                   return s
   return 'E3ROR'

def spec_crc32(key_1, key_pos, filename, start_addr, base_addr, order, species, size, count):
   res_arr = dump_data_specific(filename, start_addr, base_addr, order, species, size, 1) #dst_value must is 1*dword
   print 'order:'+str(order)+' '+str(res_arr)
   if count == 1:
       p = res_arr[0]
       if res_arr[0][-1] == 'L':
           p = res_arr[0][:-1]
       dec = explode_crc32_c1(int(p,16))
   elif count == 2:
       p = res_arr[0]
       if res_arr[0][-1] == 'L':
           p = res_arr[0][:-1]
       dec = explode_crc32_c2(int(p,16))
   elif count == 3:
       p = res_arr[0]
       if res_arr[0][-1] == 'L':
           p = res_arr[0][:-1]
       dec = explode_crc32_c3(int(p,16))
   else:
       print "Can not reach explode num"
       return "Fail"
   for i in range(count):
       key_1[key_pos+i] = dec[i]
   return key_1

def xor_swap(count):
   arr_mess = [0xDC, 0x48, 0x8F, 0x56, 0xBC, 0x36, 0xB0, 0x64, 0x40, 0x27, 0xE6, 0x2C, 0xD2, 0x3F, 0xC2, 0x34,
   0x5D, 0x52, 0xEE, 0xCD, 0xAA, 0xCA, 0x81, 0x8D, 0x71, 0x23, 0x28, 0xD7, 0x96, 0x4E, 0x7F, 0x6B,
   0xA1, 0x3E, 0xA3, 0x12, 0x91, 0x26, 0xE4, 0x03, 0x60, 0x8C, 0x01, 0x44, 0x79, 0xE3, 0x84, 0x35,
   0xB8, 0x4A, 0xC1, 0x55, 0x1A, 0x9D, 0x11, 0xE7, 0x92, 0xA4, 0xD4, 0x68, 0x37, 0x85, 0x62, 0x66,
   0xFC, 0xBF, 0xD8, 0x98, 0x9A, 0x8E, 0x32, 0x20, 0x16, 0x38, 0x57, 0x0E, 0x18, 0x5B, 0xF4, 0x17,
   0x1E, 0xA0, 0xDD, 0x53, 0x5F, 0x06, 0xF8, 0xF6, 0xE1, 0x0C, 0x02, 0x74, 0xF3, 0xC0, 0xC3, 0xF0,
   0x3C, 0x94, 0x10, 0xDB, 0x04, 0xF9, 0x08, 0xD6, 0x1F, 0xBE, 0xEF, 0x95, 0xE5, 0x50, 0xB6, 0xAB,
   0x5A, 0x19, 0xAD, 0x24, 0x99, 0x43, 0xCB, 0xA5, 0xEB, 0x39, 0xCC, 0x67, 0xB9, 0xC5, 0xC9, 0xA6,
   0x6A, 0x90, 0x7A, 0x0F, 0xD9, 0x3B, 0x1C, 0xE8, 0xA8, 0x7E, 0xC4, 0x72, 0x8B, 0x63, 0x1B, 0x59,
   0x07, 0x49, 0xAE, 0x05, 0xA9, 0xEC, 0x00, 0xC6, 0x31, 0x14, 0x69, 0xBA, 0x82, 0x1D, 0x65, 0x46,
   0x70, 0x29, 0xAF, 0xC8, 0xDE, 0xD0, 0xFD, 0x77, 0x73, 0x2B, 0x6D, 0xDF, 0x6C, 0xFE, 0x30, 0x2F,
   0xF1, 0x78, 0x21, 0x7C, 0x4D, 0xCE, 0x13, 0xB5, 0x97, 0x2A, 0x9E, 0xFF, 0xEA, 0xCF, 0x25, 0xBD,
   0xAC, 0x4C, 0x0D, 0x80, 0xE9, 0xB2, 0x4B, 0xFA, 0x54, 0x41, 0x89, 0x3A, 0x51, 0xF7, 0x00, 0x8A,
   0x2D, 0xDA, 0x33, 0xF2, 0x22, 0x9B, 0xD5, 0xA2, 0x45, 0x6E, 0x4F, 0xD3, 0x76, 0x3D, 0x86, 0x2E,
   0xBB, 0x7B, 0x0A, 0x42, 0xB1, 0x5E, 0xED, 0x9C, 0xE0, 0x88, 0x7D, 0x15, 0x93, 0xD1, 0x83, 0x6F,
   0xFB, 0xB4, 0x9F, 0x47, 0x09, 0xA7, 0x87, 0xF5, 0x61, 0xE2, 0xC7, 0xB3, 0x75, 0x0B, 0x58, 0x5C]
   add = 0
   res = []
   for i_ in range(count):
       i_ += 1
       add = (add +arr_mess[i_]) & 0xff
       arr_mess[i_] ^= arr_mess[add]
       arr_mess[add] ^= arr_mess[i_]
       arr_mess[i_] ^= arr_mess[add]
       pos = (arr_mess[i_] + arr_mess[add])&0xff
       res.append(arr_mess[pos])
   return res  

def spec_xor_swap(key_1, key_pos, filename, start_addr, base_addr, order, species, size, count):
   res_arr = dump_data_specific(filename, start_addr, base_addr, order, species, size, count)
   print 'order:'+str(order)+' '+str(res_arr)
   dst = xor_swap(count)
   for i in range(len(res_arr)):
       if(res_arr[i][-1] == 'L'):
           key_1[key_pos+i] = chr(dst[i] ^ int(res_arr[i][:-1] ,16))
       else:
           key_1[key_pos+i] = chr(dst[i] ^ int(res_arr[i],16))
   return key_1

def dec_base64(dst, read_size):
   for i in range(read_size):
       if(dst[i] == '\x00'):
           dst[i] = '='
   dst = ''.join(dst)
   this_table = ''.join(orig_bs_table)
   orig_table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
   transtab = string.maketrans(this_table, orig_table)
   dec_1 = dst.translate(transtab).decode('base64')
   return dec_1

def spec_base64(key_1, key_pos, filename, start_addr, base_addr, order, species, size, count):
   if(count % 3 !=0):
       read_size = (count/3+1)*4
   else:
       read_size = (count/3)*4
   res_arr = dump_data_specific(filename, start_addr, base_addr, order, species, size, read_size)
   print 'order:'+str(order)+' '+str(res_arr)
   dst = []
   for i in range(len(res_arr)):
       dst.append(chr(int(res_arr[i], 16)))
   dec_1 = dec_base64(dst, read_size)
   for i in range(len(dec_1)):
       key_1[key_pos+i] = dec_1[i]
   return key_1

def dec_value_shift(dst, count):
   for i in range(count):
       dst[i] = chr(dst[i]-13)
   return dst

def spec_value_shift(key_1, key_pos, filename, start_addr, base_addr, order, species, size, count):
   res_arr = dump_data_specific(filename, start_addr, base_addr, order, species, size, count)
   print 'order:'+str(order)+' '+str(res_arr)
   dst = []
   for i in range(len(res_arr)):
       dst.append((int(res_arr[i], 16)))
   dec_1 = dec_value_shift(dst, count)
   for i in range(count):
       key_1[key_pos+i] = dec_1[i]
   return key_1

def dec_value_equal(dst, count):
   for i in range(count):
       dst[i] = chr(dst[i])
   return dst

def spec_value_equal(key_1, key_pos, filename, start_addr, base_addr, order, species, size, count):
   res_arr = dump_data_specific(filename, start_addr, base_addr, order, species, size, count)
   print 'order:'+str(order)+' '+str(res_arr)
   dst = []
   for i in range(len(res_arr)):
       dst.append((int(res_arr[i], 16)))
   dec_1 = dec_value_equal(dst, count)
   for i in range(count):
       key_1[key_pos+i] = dec_1[i]
   return key_1

def dec_value_xor(dst, count):
   for i in range(count):
       dst[i] = chr(dst[i] ^ 0x2A)
   return dst

def spec_value_xor(key_1, key_pos, filename, start_addr, base_addr, order, species, size, count):
   res_arr = dump_data_specific(filename, start_addr, base_addr, order, species, size, count)
   print 'order:'+str(order)+' '+str(res_arr)
   dst = []
   for i in range(len(res_arr)):
       dst.append((int(res_arr[i], 16)))
   dec_1 = dec_value_xor(dst, count)
   for i in range(count):
       key_1[key_pos+i] = dec_1[i]
   return key_1

key_1 = ['x'] * 69

key_1 = spec_fib(key_1, 2, "magic", 0x605100, 0x600000, 0, Offst_x_data, 8, 3)
key_1 = spec_fib(key_1, 0x2c, "magic", 0x605100, 0x600000, 1, Offst_x_data, 8, 2)
key_1 = spec_crc32(key_1, 0x10, "magic", 0x605100, 0x600000, 2, Offst_x_data, 4, 1)
key_1 = spec_xor_swap(key_1, 0x7, "magic", 0x605100, 0x600000, 3, Offst_x_data, 1, 3)
key_1 = spec_base64(key_1, 0x3f, "magic", 0x605100, 0x600000, 4, Offst_x_data, 1, 1)
key_1 = spec_fib(key_1, 0x39, "magic", 0x605100, 0x600000, 5, Offst_x_data, 8, 3)
key_1 = spec_fib(key_1, 0x30, "magic", 0x605100, 0x600000, 6, Offst_x_data, 8, 2)
key_1 = spec_value_shift(key_1, 0x1e, "magic", 0x605100, 0x600000, 7, Offst_x_data, 1, 3)
key_1 = spec_value_equal(key_1, 0x0a, "magic", 0x605100, 0x600000, 8, Offst_x_data, 1, 1)
key_1 = spec_value_equal(key_1, 0x3c, "magic", 0x605100, 0x600000, 9, Offst_x_data, 1, 3)
key_1 = spec_value_shift(key_1, 0x0d, "magic", 0x605100, 0x600000, 10, Offst_x_data, 1, 1)
key_1 = spec_fib(key_1, 0x2b, "magic", 0x605100, 0x600000, 11, Offst_x_data, 8, 1)
key_1 = spec_value_shift(key_1, 0x38, "magic", 0x605100, 0x600000, 12, Offst_x_data, 1, 1)
key_1 = spec_value_xor(key_1, 0x12, "magic", 0x605100, 0x600000, 13, Offst_x_data, 1, 2)
key_1 = spec_value_equal(key_1, 0x11, "magic", 0x605100, 0x600000, 14, Offst_x_data, 1, 1)
key_1 = spec_crc32(key_1, 0x42, "magic", 0x605100, 0x600000, 15, Offst_x_data, 4, 3)
key_1 = spec_value_equal(key_1, 0x28, "magic", 0x605100, 0x600000, 16, Offst_x_data, 1, 3)
key_1 = spec_value_xor(key_1, 0x2e, "magic", 0x605100, 0x600000, 17, Offst_x_data, 1, 2)
key_1 = spec_value_shift(key_1, 0x0, "magic", 0x605100, 0x600000, 18, Offst_x_data, 1, 2)
key_1 = spec_xor_swap(key_1, 0xB, "magic", 0x605100, 0x600000, 19, Offst_x_data, 1, 2)
key_1 = spec_value_xor(key_1, 0x26, "magic", 0x605100, 0x600000, 20, Offst_x_data, 1, 2)
key_1 = spec_value_xor(key_1, 0x14, "magic", 0x605100, 0x600000, 21, Offst_x_data, 1, 2)
key_1 = spec_base64(key_1, 0x32, "magic", 0x605100, 0x600000, 22, Offst_x_data, 1, 3)
key_1 = spec_value_shift(key_1, 0x24, "magic", 0x605100, 0x600000, 23, Offst_x_data, 1, 2)
key_1 = spec_value_equal(key_1, 0x1c, "magic", 0x605100, 0x600000, 24, Offst_x_data, 1, 2)
key_1 = spec_value_equal(key_1, 0x2f, "magic", 0x605100, 0x600000, 25, Offst_x_data, 1, 1)
key_1 = spec_value_xor(key_1, 0x05, "magic", 0x605100, 0x600000, 26, Offst_x_data, 1, 2)
key_1 = spec_value_xor(key_1, 0x35, "magic", 0x605100, 0x600000, 27, Offst_x_data, 1, 3)
key_1 = spec_fib(key_1, 0x40, "magic", 0x605100, 0x600000, 28, Offst_x_data, 8, 2)
key_1 = spec_value_xor(key_1, 0x16, "magic", 0x605100, 0x600000, 29, Offst_x_data, 1, 3)
key_1 = spec_fib(key_1, 0x0e, "magic", 0x605100, 0x600000, 30, Offst_x_data, 8, 2)
key_1 = spec_value_shift(key_1, 0x19, "magic", 0x605100, 0x600000, 31, Offst_x_data, 1, 3)
key_1 = spec_value_xor(key_1, 0x21, "magic", 0x605100, 0x600000, 32, Offst_x_data, 1, 3)
print ''.join(key_1) #inds isng  llg w. e  HthitheoftheAh,urnolik inefe  yo blrhot in owace


    这样,Proc1分析完成。

     

    那么现在就有这样的问题:
    1/666的check与n/666的Check的不同。


    猜测:


    • 函数smc后地址不变,仅是调用顺序改变

    • 函数smc后地址改变,但函数类型不变

    • 函数smc后地址改变,类型改变


    难度依次递增。

     

    Proc2:


    黑箱测试:Proc2的作用是重写33个数据结构,并且会在进下一轮Proc1之前,将改动写回文件当中。
    当完成(1/666)的Proc1,我们就拿到了Proc2的bin,再用脚本还原,可以发现:
    函数虽然smc的地址改变了,但函数类型不变,都在这7种。
    那么我们就必要硬逆Proc2的算法了。



    0x02 急


    让我们梳理下执行逻辑:

    • 生成seed为proc_2更新做准备

    • 输入key 共666轮

    • Proc_1 Check

    • 解密flag 共666轮

    • Proc_2 更新文件(本地写)

    • loop到2, 直到666轮完成,输出解密flag

     

    那么我们可以在proc_2更新之前,复制出来一份。这一份的我们可以用来手动解smc从而得到33个函数,而不影响正常的proc_2过程。

     

    就算得到了33个函数,那如何实现自动化生成key呢?根据Proc_2的结果我们知道33个函数均在7种类型内,这样就可以通过某一地址上的值两两不同去识别。比如:


    •         func_fib: 48 85 C0 75

    •         func_crc32: 0F B6 00 0F

    •         func_base64: 6A 62 38 40

    •         func_xor_swap: 48 B8 61 20

    •         fubc_value_xor: 48 01 D0 8B

    •         func_value_equal: 48 01 C2 8B

    •         func_value_shift: 8B 55 FC 48


    以上是以0x30为起点的4字节值,可以注意到0x32地址上值两两不同,即可用于识别函数。


    这样,Crack思路就很清晰了:


    1.手动解smc,识别33个函数属于的种类
    2.根据种类,执行对应的解密算法
    3.使用pwntools完成recv和send的自动化。

     

    完整的Crack脚本:

    from pwn import *
    from struct import *
    import binascii
    import base64
    import string
    import shutil
    import os

    context.log_level = 'debug'
    context.terminal = ['gnome-terminal','-x','bash','-c']

    Offst_xor_func = 0x00
    Offst_func_size = 0x08
    Offst_s_start_addr = 0x0c
    Offst_s_len = 0x10
    Offst_dst_pos = 0x14
    Offst_xor_data_pos = 0x18
    Offst_x_data = 0x20

    fib_list = [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040, 1346269, 2178309, 3524578, 5702887, 9227465, 14930352, 24157817, 39088169, 63245986, 102334155, 165580141, 267914296, 433494437, 701408733, 1134903170, 1836311903, 2971215073, 4807526976, 7778742049, 12586269025, 20365011074, 32951280099, 53316291173, 86267571272, 139583862445, 225851433717, 365435296162, 591286729879, 956722026041, 1548008755920, 2504730781961, 4052739537881, 6557470319842, 10610209857723, 17167680177565, 27777890035288, 44945570212853, 72723460248141, 117669030460994, 190392490709135, 308061521170129, 498454011879264, 806515533049393, 1304969544928657, 2111485077978050, 3416454622906707, 5527939700884757, 8944394323791464, 14472334024676221, 23416728348467685, 37889062373143906, 61305790721611591, 99194853094755497, 160500643816367088, 259695496911122585, 420196140727489673, 679891637638612258, 1100087778366101931, 1779979416004714189, 2880067194370816120, 4660046610375530309, 7540113804746346429, 12200160415121876738, 1293530146158671551, 13493690561280548289, 14787220707439219840, 9834167195010216513, 6174643828739884737, 16008811023750101250, 3736710778780434371, 1298777728820984005, 5035488507601418376, 6334266236422402381, 11369754744023820757, 17704020980446223138, 10627031650760492279, 9884308557497163801, 2064596134548104464, 11948904692045268265, 14013500826593372729, 7515661444929089378, 3082418197812910491, 10598079642741999869, 13680497840554910360, 5831833409587358613, 1065587176432717357, 6897420586020075970, 7963007762452793327, 14860428348472869297, 4376692037216111008, 790376311979428689, 5167068349195539697, 5957444661174968386, 11124513010370508083, 17081957671545476469, 9759726608206432936, 8394940206042357789, 18154666814248790725, 8102862946581596898, 7810785687120836007]
    orig_bs_table = [0x2A, 0x39, 0x5F, 0x64, 0xC2, 0xA7, 0x46, 0x23,
    0x53, 0x6B, 0x74, 0x47, 0x28, 0x4D, 0x70, 0x42,
    0x49, 0x25, 0x52, 0x6A, 0x62, 0x38, 0x40, 0x4A,
    0x69, 0x45, 0x44, 0x59, 0x2D, 0x31, 0x24, 0x50,
    0x67, 0x79, 0x54, 0x21, 0x4C, 0x76, 0x71, 0x66,
    0x2B, 0x63, 0x68, 0x6D, 0x51, 0x57, 0x4F, 0x30,
    0x65, 0x4E, 0x5A, 0x34, 0x75, 0x6E, 0x33, 0x6C,
    0x37, 0x48, 0x26, 0x32, 0x77, 0x61, 0x7A, 0x4B]
    for i in range(len(orig_bs_table)):
       orig_bs_table[i] = chr(orig_bs_table[i])

    def dump_data_core(filename, data_addr, base_addr, size):
       fp= open(filename, "rb")
       offset = data_addr - base_addr
       fp.seek(offset,0)
       f = fp.read()
       type_format = '<' #default
       if size == 1:
           type_format += 'B'
       elif size == 2:
           type_format += 'H'
       elif size == 4:
           type_format += 'I'
       elif size == 8:
           type_format += 'Q'
       else:
           print "[warn]"
           type_format += 'x'
       target_data, = pack(type_format, f[:size])
       return target_data

    def dump_data_specific(filename, start_addr, base_addr, order, size, read_size):
       addr_addr = start_addr + 0x120*order + Offst_s_start_addr
       arr_addr = dump_data_core(filename, addr_addr, base_addr, 4)
       len_addr = start_addr + 0x120*order + Offst_s_len
       arr_len = dump_data_core(filename, len_addr, base_addr, 4)
       arr_data = []
       count = arr_len
       if read_size != 0:
           count = read_size
       for i in range(count):
           data_addr = start_addr + 0x120*order + Offst_x_data + i*size
           arr_data.append(hex(dump_data_core(filename, data_addr, base_addr, size)))
       return arr_addr, arr_len, arr_data

    def explode_fib_num(dst):
       for i in range(len(fib_list)):
           if(dst == fib_list[i]):
               return i-1
       return "Error"

    def spec_fib(key_1, filename, start_addr, base_addr, order):
       key_pos,count,res_arr = dump_data_specific(filename, start_addr, base_addr, order, 8, 0)
       print 'order:'+str(order)+' '+str(res_arr)
       for i in range(len(res_arr)):
           if(res_arr[i][-1] == 'L'):
               c = chr(explode_fib_num(int(res_arr[i][:-1] ,16)))
               key_1[key_pos+i] = c
           else:
               c = chr(explode_fib_num(int(res_arr[i],16)))
               key_1[key_pos+i] = c
       return key_1

    def explode_crc32_c1(dst):
       if dst == 0x0:
           return ord('X')
       for i in range(31, 127):
           if(dst == binascii.crc32(chr(i)) &0xffffffff):
               return chr(i)
       return 'E1ROR'

    def explode_crc32_c2(dst):
       if dst == 0x0:
           return ord('X')
       for x0 in range(31, 127):
           for x1 in range(31, 127):
               s = chr(x0) + chr(x1)
               if(binascii.crc32(s) &0xffffffff) == dst:
                   return s
       return 'E2ROR'

    def explode_crc32_c3(dst):
       if dst == 0x0:
           return ord('X')
       for x0 in range(31, 127):
           for x1 in range(31, 127):
               for x2 in range(31, 127):
                   s = chr(x0) + chr(x1) + chr(x2)
                   if(binascii.crc32(s) &0xffffffff) == dst:
                       return s
       return 'E3ROR'

    def spec_crc32(key_1, filename, start_addr, base_addr, order):
       key_pos,count,res_arr = dump_data_specific(filename, start_addr, base_addr, order, 4, 0)
       print 'order:'+str(order)+' '+str(res_arr)
       if count == 1:
           p = res_arr[0]
           if res_arr[0][-1] == 'L':
               p = res_arr[0][:-1]
           dec = explode_crc32_c1(int(p,16))
       elif count == 2:
           p = res_arr[0]
           if res_arr[0][-1] == 'L':
               p = res_arr[0][:-1]
           dec = explode_crc32_c2(int(p,16))
       elif count == 3:
           p = res_arr[0]
           if res_arr[0][-1] == 'L':
               p = res_arr[0][:-1]
           dec = explode_crc32_c3(int(p,16))
       else:
           print "Can not reach explode num"
           return "Fail"
       for i in range(count):
           key_1[key_pos+i] = dec[i]
       return key_1

    def xor_swap(count):
       arr_mess = [0xDC, 0x48, 0x8F, 0x56, 0xBC, 0x36, 0xB0, 0x64, 0x40, 0x27, 0xE6, 0x2C, 0xD2, 0x3F, 0xC2, 0x34,
       0x5D, 0x52, 0xEE, 0xCD, 0xAA, 0xCA, 0x81, 0x8D, 0x71, 0x23, 0x28, 0xD7, 0x96, 0x4E, 0x7F, 0x6B,
       0xA1, 0x3E, 0xA3, 0x12, 0x91, 0x26, 0xE4, 0x03, 0x60, 0x8C, 0x01, 0x44, 0x79, 0xE3, 0x84, 0x35,
       0xB8, 0x4A, 0xC1, 0x55, 0x1A, 0x9D, 0x11, 0xE7, 0x92, 0xA4, 0xD4, 0x68, 0x37, 0x85, 0x62, 0x66,
       0xFC, 0xBF, 0xD8, 0x98, 0x9A, 0x8E, 0x32, 0x20, 0x16, 0x38, 0x57, 0x0E, 0x18, 0x5B, 0xF4, 0x17,
       0x1E, 0xA0, 0xDD, 0x53, 0x5F, 0x06, 0xF8, 0xF6, 0xE1, 0x0C, 0x02, 0x74, 0xF3, 0xC0, 0xC3, 0xF0,
       0x3C, 0x94, 0x10, 0xDB, 0x04, 0xF9, 0x08, 0xD6, 0x1F, 0xBE, 0xEF, 0x95, 0xE5, 0x50, 0xB6, 0xAB,
       0x5A, 0x19, 0xAD, 0x24, 0x99, 0x43, 0xCB, 0xA5, 0xEB, 0x39, 0xCC, 0x67, 0xB9, 0xC5, 0xC9, 0xA6,
       0x6A, 0x90, 0x7A, 0x0F, 0xD9, 0x3B, 0x1C, 0xE8, 0xA8, 0x7E, 0xC4, 0x72, 0x8B, 0x63, 0x1B, 0x59,
       0x07, 0x49, 0xAE, 0x05, 0xA9, 0xEC, 0x00, 0xC6, 0x31, 0x14, 0x69, 0xBA, 0x82, 0x1D, 0x65, 0x46,
       0x70, 0x29, 0xAF, 0xC8, 0xDE, 0xD0, 0xFD, 0x77, 0x73, 0x2B, 0x6D, 0xDF, 0x6C, 0xFE, 0x30, 0x2F,
       0xF1, 0x78, 0x21, 0x7C, 0x12, 0xCE, 0x13, 0xB5, 0x97, 0x2A, 0x9E, 0xFF, 0xEA, 0xCF, 0x25, 0xBD,
       0xAC, 0x4C, 0x0D, 0x80, 0xE9, 0xB2, 0x4B, 0xFA, 0x54, 0x41, 0x89, 0x3A, 0x51, 0xF7, 0x00, 0x8A,
       0x2D, 0xDA, 0x33, 0xF2, 0x22, 0x9B, 0xD5, 0xA2, 0x45, 0x6E, 0x4F, 0xD3, 0x76, 0x3D, 0x86, 0x2E,
       0xBB, 0x7B, 0x0A, 0x42, 0xB1, 0x5E, 0xED, 0x9C, 0xE0, 0x88, 0x7D, 0x15, 0x93, 0xD1, 0x83, 0x6F,
       0xFB, 0xB4, 0x9F, 0x47, 0x09, 0xA7, 0x87, 0xF5, 0x61, 0xE2, 0xC7, 0xB3, 0x75, 0x0B, 0x58, 0x5C]
       add = 0
       res = []
       for i_ in range(count):
           i_ += 1
           add = (add +arr_mess[i_]) & 0xff
           arr_mess[i_] ^= arr_mess[add]
           arr_mess[add] ^= arr_mess[i_]
           arr_mess[i_] ^= arr_mess[add]
           pos = (arr_mess[i_] + arr_mess[add])&0xff
           res.append(arr_mess[pos])
       return res  

    def spec_xor_swap(key_1, filename, start_addr, base_addr, order):
       key_pos,count,res_arr = dump_data_specific(filename, start_addr, base_addr, order, 1, 0)
       print 'order:'+str(order)+' '+str(res_arr)
       dst = xor_swap(count)
       for i in range(len(res_arr)):
           if(res_arr[i][-1] == 'L'):
               key_1[key_pos+i] = chr(dst[i] ^ int(res_arr[i][:-1] ,16))
           else:
               key_1[key_pos+i] = chr(dst[i] ^ int(res_arr[i],16))
       return key_1

    def dec_base64(dst, read_size):
       for i in range(read_size):
           if(dst[i] == '\x00'):
               dst[i] = '='
       dst = ''.join(dst)
       this_table = ''.join(orig_bs_table)
       orig_table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
       transtab = string.maketrans(this_table, orig_table)
       dec_1 = dst.translate(transtab).decode('base64')
       return dec_1

    def spec_base64(key_1, filename, start_addr, base_addr, order):
       key_pos,count,res_arr = dump_data_specific(filename, start_addr, base_addr, order, 1, 0)
       if(count % 3 !=0):
           read_size = (count/3+1)*4
       else:
           read_size = (count/3)*4
       key_pos,count,res_arr = dump_data_specific(filename, start_addr, base_addr, order, 1, read_size)
       print 'order:'+str(order)+' '+str(res_arr)
       dst = []
       for i in range(len(res_arr)):
           dst.append(chr(int(res_arr[i], 16)))
       dec_1 = dec_base64(dst, read_size)
       for i in range(len(dec_1)):
           key_1[key_pos+i] = dec_1[i]
       return key_1

    def dec_value_shift(dst, count):
       for i in range(count):
           dst[i] = chr(dst[i]-13)
       return dst

    def spec_value_shift(key_1, filename, start_addr, base_addr, order):
       key_pos,count,res_arr = dump_data_specific(filename, start_addr, base_addr, order, 1, 0)
       print 'order:'+str(order)+' '+str(res_arr)
       dst = []
       for i in range(len(res_arr)):
           dst.append((int(res_arr[i], 16)))
       dec_1 = dec_value_shift(dst, count)
       for i in range(count):
           key_1[key_pos+i] = dec_1[i]
       return key_1

    def dec_value_equal(dst, count):
       for i in range(count):
           dst[i] = chr(dst[i])
       return dst

    def spec_value_equal(key_1, filename, start_addr, base_addr, order):
       key_pos,count,res_arr = dump_data_specific(filename, start_addr, base_addr, order, 1, 0)
       print 'order:'+str(order)+' '+str(res_arr)
       dst = []
       for i in range(len(res_arr)):
           dst.append((int(res_arr[i], 16)))
       dec_1 = dec_value_equal(dst, count)
       for i in range(count):
           key_1[key_pos+i] = dec_1[i]
       return key_1

    def dec_value_xor(dst, count):
       for i in range(count):
           dst[i] = chr(dst[i] ^ 0x2A)
       return dst

    def spec_value_xor(key_1, filename, start_addr, base_addr, order):
       key_pos,count,res_arr = dump_data_specific(filename, start_addr, base_addr, order, 1, 0)
       print 'order:'+str(order)+' '+str(res_arr)
       dst = []
       for i in range(len(res_arr)):
           dst.append((int(res_arr[i], 16)))
       dec_1 = dec_value_xor(dst, count)
       for i in range(count):
           key_1[key_pos+i] = dec_1[i]
       return key_1

    func_spec = [spec_fib, spec_crc32, spec_base64, spec_xor_swap, spec_value_xor, spec_value_equal, spec_value_shift]
               #0            1            2            3                4                5                    6

    def deal_file():
       if(os.path.exists("magic_dsmc")):
           os.remove("magic_dsmc")
       shutil.copy("magic", "magic_dsmc")
       fp_r = open("magic", "rb")
       fp_w = open("magic_dsmc", "rb+")
       return fp_r, fp_w

    def dec_smc_core(func_addr, size, xor_addr, fp_o, fp_w):
       fp_o.seek(0,0)
       f_r = fp_o.read()
       res = ''
       for i in range(size):
           res += chr(ord(f_r[func_addr+i]) ^ ord(f_r[xor_addr+i]))
       fp_w.seek(func_addr, 0)
       fp_w.write(res)

    def dec_smc(fp_r, fp_w):
       fp_r.seek(0x5100, 0)
       f_r = fp_r.read()
       func_pos = []
       for i in range(33):
           xor_func, xor_size, len_p1, len_p2, dst_pos, xor_data_pos = pack("<q4iq", f_r[i*0x120:i*0x120+32])
           xor_func -= 0x400000
           xor_data_pos -= 0x600000
           dec_smc_core(xor_func, xor_size, xor_data_pos, fp_r, fp_w)
           func_pos.append(xor_func)
       return func_pos

    def verify_func(func_pos, fp_w):
       fp_w.seek(0,0)
       f_w = fp_w.read()
       func_list = []
       for i in range(33):
           sig_addr = func_pos[i] + 0x56
           sig_value, = pack("<H", f_w[sig_addr:sig_addr+1])
           print i, hex(sig_value)
           if sig_value == 0xC0:
               func_list.append(0) # fib
           elif sig_value == 0x00:
               func_list.append(1) # crc32
           elif sig_value == 0x38:
               func_list.append(2) # base64
           elif sig_value == 0x61:
               func_list.append(3) # xor_swap
           elif sig_value == 0xD0:
               func_list.append(4) # value_xor
           elif sig_value == 0xC2:
               func_list.append(5) # value_equal
           elif sig_value == 0xFC:
               func_list.append(6) # value_shift
           else:
               print "Critcal Error!!!"
               return -1
       return func_list

    def get_func_list():
       fp_r, fp_w = deal_file()
       func_pos = dec_smc(fp_r, fp_w)
       func_list = verify_func(func_pos, fp_w)
       return func_list

    def ch_run(func_list):
       key_1 = ['x'] * 69
       for i in range(len(func_list)):
           ptr_f = func_spec[func_list[i]]
           key_1 = ptr_f(key_1, "magic", 0x605100, 0x600000, i)
       return ''.join(key_1)

    def deal_key(i):
       print "#-------Ch%d--------#"%i
       func_list = get_func_list()
       key_d = ch_run(func_list)
       return key_d

    def Crack():
       sh = process('./magic',shell=True)
       bin = ELF('./magic')
       sleep(0)
       for i in range(666):
           sh.recvuntil('Enter key:')
           input_key = deal_key(i)
           sh.sendline(input_key)
       sh.recvuntil('Congrats! Here is your price:')

    Crack()



    0x03 终


    最后,因为Flare-on5直到Oct.5才结束,所以以上的脚本都被我轻微的改动了一下。

    本人仅仅提供一点点思路,还请各位Cracker斧正。

    更新了附件, password: infected。




    - End -



    看雪ID:蒼V嵐   

    https://bbs.pediy.com/user-738599.htm




    本文由看雪论坛 蒼V嵐 原创

    转载请注明来自看雪社区






    热门技术文章推荐:






    戳原文,看看大家都是怎么说的?

      您可能也对以下帖子感兴趣

      文章有问题?点此查看未经处理的缓存